Broker Chain

Pointer Chain을 이용한 디자인 패턴에서 사슬은 매우 인위적이다.
책임 사슬을 구현하는 또 다른 방법은 중앙 집중화된 컴포넌트를 이용하는 것이다.
(해당 컴포넌트에서 게임에서 발생하는 모든 변경 작업의 목록을 관리- 이벤트 브로커)

이벤트 브로커는 매개자(mediator) 디자인 패턴이자, 관찰자(observer) 디자인 패턴이다.
struct Game{ // 매개자
signal<void(Query&)> queries;
}; // Boost.Signals2 라이브러리의 signal
크리처의 필드를 읽는 작업은, 변경 작업 후 결과값이 확정난 이후가 되어야 한다.
조회 작업을 별도의 객체에 캡슐화해서 처리(커맨드 패턴)
// 조회 작업을 위한 커맨드 패턴 클래스
struct Query{
string creature_name;
enum Argument{attack, defense} argument; // 조회하기 위한 상태값
int result;
};
class Creature{
Game& game;
int attack, defense;
public:
string name;
// Creature(Game& game, ...): game(gmae), ... { ... }
// ...
};
int Creature::get_attach() const {
Query q{name, Query::Argument::attack, attack};
game.queries(q); // game에서 시그널을 받으면 q.result를 수정
return q.result;
}
// 변경 작업
class CreatureModifier{
Game& game;
Creature& creature;
public:
CreatureModifier(Game& game, Creature& creature): game(game), creature(creature) {}
};
class DoubleAttackModifier: public CreatureModifier{
connection conn;
public:
DoubleAttackModifier(Game& game, Creature& creature): CreatureModifier(game, creature){
conn=gamequeries.connect([&](Query& q){ // 람다 함수를 연결
if(q.creature_name==creature.name &&
q.argument==Query::Argument::attack) q.result*=2;
});
}
~DoubleAttackModifier(){ conn.disconnect(); }
};
// 사용
Game game;
Creature goblin{game, "Strong Goblin", 2, 2};
cout<<goblin<<endl;
// 이름: Strong Goblin 공격력: 2 방어력: 2
{
DoubleAttackModifier dam{game, goblin};
cout<<goblin<<endl;
// 이름: Strong Goblin 공격력: 4 방어력: 2
} // 범위 밖에서 dam 소멸자 호출(브로커와 연결을 끊음)
cout<<goblin<<endl;
// 이름: Strong Goblin 공격력: 2 방어력: 2